﻿using System;
using System.Collections.Generic;
using G.Runtime.Action;
using G.Runtime.Actions;
using GameLibrary.Internal;
using G.Model;
using GameRuntimeLibrary.Model.Runtime.Actions;
using G.Model.Enums;

namespace G.Runtime
{
    public class GameElement : HasValues
    {
        public class LocationChangedEventArgs : EventArgs 
        {
            public GameLocation oldLocation;
            public GameLocation newLocation;
            public GameElement element;
        }
        
        public delegate void LocationChangedHandler(LocationChangedEventArgs args);
        
        public event LocationChangedHandler LocationChanged;
        
        private readonly GameSpace _Game;
        private readonly GameValues _GameValues;
        private readonly GameElementDef _ElementDef;
        
        private GameLocation _Location;
        private string _Player;
        private string _Icon;
        private string _Text;

        public GameElement(GameElementDef pElementDef, GameSpace pGame)
        {
            _ElementDef = pElementDef;
            _Game = pGame;
            _Location = pElementDef.Location;
            _Player = pElementDef.Player;
            _Icon = pElementDef.Icon;
            _Text = pElementDef.Text;
            _GameValues = new GameValues(pElementDef.GameValueDefs);
            _GameValues.ChangedEvent += delegate(GameValues pGameValues) 
            {
                GamePlayer player = _Game.Players[_Player];
                player.GameValues.FireChangedEvent();
            };
        }

        public GameSpace Game
        {
            get { return _Game; }
        }
        
        public GameLocation Location
        {
            get { return _Location; }
            set { _Game.Elements.SetPosition(this, value); }
        }
        
        internal void SetLocation(GameLocation value) 
        {
            _Location = value;
        }

        public GameElementDef Def
        {
            get { return _ElementDef; }
        }

        public string Text
        {
            get { return _Text; }
            set 
            {
                if (_Text != value)
                {
                    _Text = value;
                    _Game.Elements.FireElementPropertyChanged(this);
                }
            }
        }
        
        public string Icon
        {
            get { return _Icon; }
            set 
            {
                if (_Icon != value)
                {
                    _Icon = value;
                    _Game.Elements.FireElementPropertyChanged(this);
                }
            }
        }

        public CollisionStratagyEnum CollisionStratagy
        {
            get { return _ElementDef.CollisionStratagy; }
        }

        public string Player
        {
            get { return _Player; }
            set 
            {
                if (_Player != value)
                { 
                    _Game.Elements.FirePlayerChanging(this);
                    _Player = value;
                    _Game.Elements.FirePlayerChanged(this);
                    _Game.Elements.FireElementPropertyChanged(this);
                 }
            }
        }

        public bool IsOwned
        {
            get { return (_Player.Length > 0 && _Player != "Nothing"); }
        }

        public List<GameAction> Actions
        {
            get
            {
                List<GameAction> result = new List<GameAction>();
                foreach (GameLocation point in MovePoints)
                {
                    GameElement e = null;
                    if (_Game.Elements.Contains(point))
                    {
                        GameElement ge = _Game.Elements[point];
                        if (ge.CollisionStratagy == CollisionStratagyEnum.CONSUME)
                        {
                            e = _Game.Elements[point];
                            result.Add(new ConsumeAction(this, e));
                        }
                        else if (ge.IsOwned == false)
                        {
                            e = _Game.Elements[point];
                            result.Add(new OwnAction(this, e));
                        }
                        else if (ge.Player != this.Player)
                        {
                            e = _Game.Elements[point];
                            result.Add(new FightAction(this, e));
                        }
                    }
                    else
                    {
                        result.Add(new MoveAction(this, point));
                    }
                }
                return result;
            }
        }

        public ICollection<GameLocation> MovePoints
        {
            get
            {
                MovePointGenerator g = new MovePointGenerator();
                g.Start = Location;
                g.Moves = this._ElementDef.MoveStratagy;
                return g.Generate();
            }
        }

        public GameValues GameValues
        {
            get { return _GameValues; }
        }

        public void Delete() 
        {
            _Game.Elements.Remove(this.Location);
        }
        
        public void FireLocationChanged(GameLocation oldLocation)
        {
            if (LocationChanged != null)
            {
                LocationChangedEventArgs args = new LocationChangedEventArgs();
                args.element = this;
                args.newLocation = this._Location;
                args.oldLocation = oldLocation;
                LocationChanged(args);
            }
        }
        
        internal void FireElementMoved()
        {
            _Game.Elements.FireElementMoved(this);
        }
        
        public override string ToString()
        {
            return _ElementDef.ToString();
        }

    }
}
